package com.hz.example.logic;

import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 数组 排列组合
 *
 * @author hezhao created on 2020/4/27 14:07
 */
public class TestArrayArrangement {

    public static void main(String[] args) {
//        test1();
//        test2();
        test3();
    }


    ///////////////////////////////////////////////////////////////////////////////
    public static void test1() {
        List<String> str1 = Lists.newArrayList("1", "2", "3", "4");
        List<List<String>> s = str(str1);
        System.out.println(s);
    }

    /** 求数组中所有的组合数组, 穷举 */
    public static List<List<String>> str(List<String> list) {
        //List结合中装的是每个小的组合list
        List<List<String>> result = new ArrayList<>();
        //总共的组合个数
        long n = (long) Math.pow(2, list.size());
        //每个组合的list
        List<String> combine;
        //循环0-组合次数
        for (long l = 0L; l < n; l++) {
            //创建每个装list的组合
            combine = new ArrayList<>();
            //遍历数组
            for (int i = 0; i < list.size(); i++) {
                //>>>指的是无符号右移
                if ((l >>> i & 1) == 1) {
                    combine.add(list.get(i));
                }
            }
            result.add(combine);
        }
        return result;
    }
    ///////////////////////////////////////////////////////////////////////////////



    ///////////////////////////////////////////////////////////////////////////////
    /** 列出N个数组所有的组合 */
    public static void test2() {
        String[] arr1 = {"Iphone X", "Iphone 11", "Iphone 6"};
        String[] arr2 = {"红色", "金色"};
        String[] arr3 = {"32G", "64G"};
        List<String[]> list = new ArrayList<>();
        list.add(arr1);
        list.add(arr2);
        list.add(arr3);
        test(list, arr1, "");
    }

    public static void test(List<String[]> list, String[] arr, String str) {
        for (int i = 0; i < list.size(); i++) {
            //取得当前的数组
            if (i == list.indexOf(arr)) {
                //迭代数组
                for (String st : arr) {
                    st = str + ", " + st;
                    if (i < list.size() - 1) {
                        test(list, list.get(i + 1), st);
                    } else if (i == list.size() - 1) {
                        System.out.println(st);
                    }
                }
            }
        }
    }
    ///////////////////////////////////////////////////////////////////////////////



    ///////////////////////////////////////////////////////////////////////////////
    public static void test3() {
        List<String> list = Lists.newArrayList("123".split(""));
        System.out.println(permutation(list, 3));
        // 输出： [111, 112, 113, 121, 122, 123, 131, 132, 133, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321, 322, 323, 331, 332, 333]
        System.out.println(permutationNoRepeat(list, 3));
        // 输出： [123, 132, 213, 231, 312, 321]


        System.out.println(permutationNoRepeat(Lists.newArrayList("诗夕舞与辰落名随叶".split("")), 4));
    }

    /**
     * 排列组合（字符重复排列）<br>
     * 内存占用：需注意结果集大小对内存的占用（list:10位，length:8，结果集:[10 ^ 8 = 100000000]，内存占用:约7G）
     * @param list 待排列组合字符集合
     * @param length 排列组合生成的字符串长度
     * @return 指定长度的排列组合后的字符串集合
     * @author www@yiynx.cn
     */
    public static List<String> permutation(List<String> list, int length) {
        Stream<String> stream = list.stream();
        for (int n = 1; n < length; n++) {
            stream = stream.flatMap(str -> list.stream().map(str::concat));
        }
        return stream.collect(Collectors.toList());
    }

    /**
     * 排列组合(字符不重复排列)<br>
     * 内存占用：需注意结果集大小对内存的占用（list:10位，length:8，结果集:[10! / (10-8)! = 1814400]）
     * @param list 待排列组合字符集合(忽略重复字符)
     * @param length 排列组合生成长度
     * @return 指定长度的排列组合后的字符串集合
     * @author www@yiynx.cn
     */
    public static List<String> permutationNoRepeat(List<String> list, int length) {
        Stream<String> stream = list.stream().distinct();
        for (int n = 1; n < length; n++) {
            stream = stream.flatMap(str -> list.stream()
                    .filter(temp -> !str.contains(temp))
                    .map(str::concat));
        }
        return stream.collect(Collectors.toList());
    }

    ///////////////////////////////////////////////////////////////////////////////



}
